﻿#region License
/* ---------------------------------------------------------------- *
 *
 * This file is part of the API Concepts Framework
 * http://apiconceptsframework.codeplex.com
 *
 * Copyright (C) 2014 eva Kühn, Thomas Scheller, Vienna University of Technology
 * http://www.complang.tuwien.ac.at/eva
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see http://www.gnu.org/licenses/
 *
 * ---------------------------------------------------------------- */
#endregion

using ApiConceptsFramework.Concepts;
using ApiConceptsFramework.Contract;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace ApiConceptsFramework.HCs
{
	/// <summary>
	/// Factory Pattern:
	/// - When a static method call returns an instance from a class of the API
	/// - When the method is not used as an extension method
	/// </summary>
	public class Factory : IHighLevelConcept
	{
		//UPDATE: No additional complexity - this is now completely displayed just by correctly balancing the usage complexity of ClassUsage!!
		//public const float AdditionalMethodComplexity = 2; //why not +20: actually the increased complexity mainly comes from the method search times (in Study 1 this was measured as "usage"), so only a very minor increase of the usage time is needed
		//public const float MaxLearningReduction = 0.5f; //+10 at the beginning, +5s when learned -> 50% learning effect
		//public const int LearningSteps = 2;
		//private static readonly LearningEffect LearningEffect = new LearningEffect(MaxLearningReduction, LearningSteps);

		public HcEvaluationResult Evaluate(List<Assembly> apiAssemblies, IEnumerable<ConceptInstance> data, IHcEvaluationInput hcInputData, IEnumerable<HcEvaluationResult> otherHcData, IDE ide = IDE.VisualStudioOrSimilar)
		{
			//(the factory pattern doesn't have any HC-specific input data)
			var staticMethods = data.Where(c => 
				c.Concept is MethodCall && 
				c.Target.Member.IsStatic() && 
				c.Target.Type == c.Target.Member.DeclaringType); //this check filters out extension methods

			int usages = 0;
			foreach (var conceptInstance in staticMethods.Where(c => apiAssemblies.Contains(((MethodInfo)c.Target.Member).ReturnType.Assembly)))
			{
				for (int i = 0; i < conceptInstance.NumberOfUsages; i++)
				{
					usages++;
					conceptInstance.HcData.Add(new HcComplexityData
						{
							HighLevelConcept = this,
							Description = "Factory Method"
							//UsageComplexity = AdditionalMethodComplexity //LearningEffect.CalculateComplexity(AdditionalMethodComplexity, usages, conceptInstance.PreviousUsages)
						});
				}
			}
			if (usages == 0)
				return null;

			return new HcEvaluationResult
				       {
					       GeneralComplexity = 0,
						   HighLevelConcept = this,
						   GeneralSuggestions = new List<string> { "Use the factory pattern only when there are many instantiation options, otherwise normal instantiation should be preferred!" }
				       };
		}

		public Type InputDataType
		{
			get { return null; } //HC factory has no input data
		}
	}
}
